﻿using System.Collections.Generic;

namespace ZSW.Framework.TimerManager
{
    public class TimerNode
    {
        public int TimerID;
        public bool IsRemoved;

        public ZSWF_TimerManager.TimerHandler Callback;
        public float Duration;
        public float Delay;
        public int Repeat;
        public float PassedTime;
        public object Param;
    }

    /// <summary>
    /// 计时器
    /// </summary>
    public class ZSWF_TimerManager : ZSWF_Singleton<ZSWF_TimerManager>
    {
        public delegate void TimerHandler(object param);

        private int AutoIncreaseID = 1; // 自增ID

        private Dictionary<int, TimerNode> m_allTimers = new Dictionary<int, TimerNode>();
        private List<TimerNode> m_removeTimers = new List<TimerNode>();
        private List<TimerNode> m_newTimers = new List<TimerNode>();

        private void Update()
        {
            float dt = UnityEngine.Time.deltaTime;

            for (int i = 0; i < m_newTimers.Count; i++)
            {
                m_allTimers.Add(m_newTimers[i].TimerID, m_newTimers[i]);
            }

            m_newTimers.Clear();

            foreach (TimerNode timer in m_allTimers.Values)
            {
                if (timer.IsRemoved)
                {
                    m_removeTimers.Add(timer);
                    continue;
                }

                ;

                timer.PassedTime += dt;
                if (timer.PassedTime >= timer.Delay + timer.Duration)
                {
                    timer.Callback(timer.Param);
                    timer.Repeat--;
                    timer.PassedTime -= (timer.Delay + timer.Duration);
                    timer.Delay = 0; // 只有第一次才需要 Delay
                    if (timer.Repeat == 0)
                    {
                        timer.IsRemoved = true;
                    }
                }
            }

            for (int i = 0; i < m_removeTimers.Count; i++)
            {
                m_allTimers.Remove(m_removeTimers[i].TimerID);
            }

            m_removeTimers.Clear();
        }

        public int ScheduleOnce(TimerHandler func, float delay = 0.0f)
        {
            return Schedule(func, null, 1, 0, delay);
        }

        public int ScheduleOnce(TimerHandler func, object param, float delay = 0.0f)
        {
            return Schedule(func, param, 1, 0, delay);
        }

        public int ScheduleLoop(TimerHandler func, float interval, float delay = 0.0f)
        {
            return Schedule(func, null, -1, interval, delay);
        }

        public int Schedule(TimerHandler func, int repeat, float duration, float delay = 0.0f)
        {
            return Schedule(func, null, repeat, duration, delay);
        }

        public int Schedule(TimerHandler func, object param, int repeat, float duration, float delay = 0.0f)
        {
            TimerNode timer = new TimerNode();
            timer.Callback = func;
            timer.Delay = delay;
            timer.Duration = duration;
            timer.Param = param;
            timer.Repeat = repeat;
            timer.PassedTime = duration;
            timer.TimerID = AutoIncreaseID;
            timer.IsRemoved = false;
            AutoIncreaseID++;
            m_newTimers.Add(timer);

            return timer.TimerID;
        }

        public void Unschedule(int timerId)
        {
            if (!m_allTimers.ContainsKey(timerId)) return;

            TimerNode timer = m_allTimers[timerId];
            timer.IsRemoved = true;
        }

        public void Unschedule(TimerHandler func)
        {
            foreach (TimerNode timer in m_allTimers.Values)
            {
                if (timer.Callback == func)
                {
                    timer.IsRemoved = true;
                }
            }
        }
    }
}